package com.google.gwt.indexeddb.client;

import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArrayString;

/**
 * An object store is the primary storage mechanism for storing data in a database.
 * 
 * @author Chan Le <gwt /at/ chanvn.com>
 * @see <a href="http://www.w3.org/TR/IndexedDB/#idl-def-IDBObjectStore">W3C IDBObjectStore</a>
 */
public class IDBObjectStore extends JavaScriptObject {

  protected IDBObjectStore() {
  }

  /**
   * Returns an IDBRequest object, and, in a separate thread, creates a structured clone of the
   * value, and stores the cloned value in the object store. If the record is successfully stored,
   * then a success event is fired on the returned request object, using the IDBTransactionEvent
   * interface, with the result set to the key for the stored record, and transaction set to the
   * transaction in which this object store is opened. If a record already exists in the object
   * store with the key parameter as its key, then an error event is fired on the returned request
   * object, with code set to CONSTRAINT_ERR.
   * 
   * @param value he value to be stored.
   * @param key The key to use to identify the record. If unspecified, it results to null.
   * @return A request object on which subsequent events related to this operation are fired.
   * @throws IDBDatabaseException
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-add">W3C
   *      IDBObjectStore-add</a>
   */
  public final IDBRequest add(Object value, Object key) throws IDBDatabaseException {
    try {
      return add0(value, key);
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native IDBRequest add0(Object value, Object key) /*-{
		return this.add(value, key);
  }-*/;

  /**
   * If the mode of the transaction that this object store belongs to is READ_ONLY, this method
   * raises an IDBDatabaseException with its code set to READ_ONLY_ERR. Otherwise, this method
   * creates and immediately returns an IDBRequest object, and clears this object store in a
   * separate thread. Clearing an object store consists of removing all records from the object
   * store and removing all records in indexes that reference the object store.
   * 
   * @return A request object on which subsequent events related to this operation are fired.
   * @throws IDBDatabaseException
   * @see <a href="http://www.w3.org/TR/IndexedDB/#object-store">W3C </a>
   */
  public final IDBRequest clear() throws IDBDatabaseException {
    try {
      return clear0();
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native IDBRequest clear0() /*-{
		return this.clear();
  }-*/;

  /**
   * Creates and returns a new index in the connected database. Note that this method must be called
   * only from a VERSION_CHANGE transaction callback.
   * 
   * @param name The name of the index to create
   * @param keyPath The key path for the index to use
   * @param unique If true, the index must not allow duplicate values for a single key.
   * @return The newly created index.
   * @throws IDBDatabaseException
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-createIndex">W3C
   *      IDBObjectStore-createIndex</a>
   */
  public final IDBIndex createIndex(String name, String keyPath, boolean unique)
      throws IDBDatabaseException {
    try {
      return createIndex0(name, keyPath, unique);
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native IDBIndex createIndex0(String name, String keyPath, boolean unique) /*-{
		return this.createIndex(name, keyPath, unique);
  }-*/;

  /**
   * Immediately returns an IDBRequest object, and removes the record specified by the given key
   * from this object store, and any indexes that reference it, in a separate thread. If no record
   * exists in this object store corresponding to the key, an error event is fired on the returned
   * request object, with its code set to NOT_FOUND_ERR and an appropriate message. If the record is
   * successfully removed, then a success event is fired on the returned request object, using the
   * IDBTransactionEvent interface, with the result set to the value of the removed record, and
   * transaction set to the transaction in which this object store is opened.
   * 
   * @param key The key to use to identify the record.
   * @throws IDBDatabaseException
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-delete">W3C
   *      IDBObjectStore-delete</a>
   */
  public final IDBRequest delete(Object key) throws IDBDatabaseException {
    try {
      return delete0(key);
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native IDBRequest delete0(Object key) /*-{
		//string property access to avoid the warning from using reserved keyword
		return this['delete'](key);
  }-*/;

  /**
   * Destroys the index with the specified name in the connected database. Note that this method
   * must be called only from a VERSION_CHANGE transaction callback.
   * 
   * @param indexName The name of the existing index to remove.
   * @throws IDBDatabaseException
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-deleteIndex">W3C
   *      IDBObjectStore-deleteIndex</a>
   */
  public final void deleteIndex(String indexName) throws IDBDatabaseException {
    try {
      deleteIndex0(indexName);
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native void deleteIndex0(String indexName) /*-{
		this.deleteIndex(indexName);
  }-*/;

  /**
   * Immediately returns an IDBRequest object, and retrieves the requested record from the object
   * store in a separate thread. If the operation is successful, then a success event is fired on
   * the returned object, using the IDBTransactionEvent interface, with its result set to the
   * retrieved value, and transaction set to the transaction in which this object store is opened.
   * If a record does not exist in the object store for the key parameter, then an error event is
   * fired on the returned object, with its code set to NOT_FOUND_ERR and an appropriate message.
   * 
   * @param key The key identifying the record to retrieve.
   * @return A request object on which subsequent events related to this operation are fired.
   * @throws IDBDatabaseException
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-get">W3C
   *      IDBObjectStore-get</a>
   */
  public final IDBRequest get(Object key) throws IDBDatabaseException {
    try {
      return get0(key);
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native IDBRequest get0(Object key) /*-{
		return this.get(key);
  }-*/;

  /**
   * @return A list of the names of indexes on objects in this object store.
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-indexNames">W3C
   *      IDBObjectStore-indexNames</a>
   */
  public final native JsArrayString getIndexNames()/*-{
		return this.indexNames;
  }-*/;

  /**
   * @return The key path of this object store. If this attribute is null, the application must
   *         provide a key for each modification operation.
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-keyPath">W3C
   *      IDBObjectStore-keyPath</a>
   */
  public final native String getKeyPath() /*-{
		return this.keyPath;
  }-*/;

  /**
   * @return The name of this object store.
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-name">W3C
   *      IDBObjectStore-name</a>
   */
  public final native String getName() /*-{
		return this.name;
  }-*/;

  /**
   * Opens the named index in this object store.
   * 
   * @param name The name of the index to open.
   * @return An object for accessing the index.
   * @throws IDBDatabaseException
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-index">W3C
   *      IDBObjectStore-index</a>
   */
  public final IDBIndex index(String name) throws IDBDatabaseException {
    try {
      return index0(name);
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native IDBIndex index0(String name) /*-{
		return this.index(name);
  }-*/;

  /**
   * Immediately returns an IDBRequest object, and creates a cursor over the records in this object
   * store, in a separate thread. If there is even a single record that matches the key range, then
   * a success event is fired on the returned object, with its result set to the IDBCursor object
   * for the new cursor. If no records match the key range, then a success event is fired on the
   * returned object, with its result set to null.
   * 
   * @param range The key range to use as the cursor's range. If this parameter is unspecified or
   *          null, then the range includes all the records in the object store.
   * @param direction The cursor's direction.
   * @return A request object on which subsequent events related to this operation are fired.
   * @throws IDBDatabaseException
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-openCursor">W3C
   *      IDBObjectStore-openCursor</a>
   */
  public final IDBRequest openCursor(IDBKeyRange range, int direction) throws IDBDatabaseException {
    try {
      return openCursor0(range, direction);
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native IDBRequest openCursor0(IDBKeyRange range, int direction) /*-{
		return this.openCursor(range, direction);
  }-*/;

  public final IDBRequest openCursor() throws IDBDatabaseException {
    try {
      return openCursor0();
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native IDBRequest openCursor0() /*-{
		return this.openCursor();
  }-*/;

  /**
   * Returns an IDBRequest object, and, in a separate thread, creates a structured clone of the
   * value, and stores the cloned value in the object store. If the record is successfully stored,
   * then a success event is fired on the returned request object, using the IDBTransactionEvent
   * interface, with the result set to the key for the stored record, and transaction set to the
   * transaction in which this object store is opened.
   * 
   * @param value The value to be stored.
   * @param key The key to use to identify the record. If unspecified, it results to null.
   * @return A request object on which subsequent events related to this operation are fired.
   * @throws IDBDatabaseException
   * @see <a href="http://www.w3.org/TR/IndexedDB/#widl-IDBObjectStore-put">W3C
   *      IDBObjectStore-put</a>
   */
  public final IDBRequest put(Object value, Object key) throws IDBDatabaseException {
    try {
      return put0(value, key);
    } catch (JavaScriptException e) {
      throw new IDBDatabaseException(e.getName(), e);
    }
  }

  private final native IDBRequest put0(Object value, Object key) /*-{
		return this.put(value, key);
  }-*/;

}
